package algo_utils

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"hash"
	"os"
)

// @author
// @version 1.0
// @date 2020-02-11 15:11
// @author-Email
// @description 加密工具

type EncryptTools struct {
	privateKey *rsa.PrivateKey
	md5Tools hash.Hash
}

// https://www.likecs.com/show-306778371.html
func (tools *EncryptTools) Md5Decrypt(msg string) (string, error) {
	//tools.md5Tools.Reset()
	ans, err := hex.DecodeString(msg)
	return cast.ToString(ans), err
}

func (tools *EncryptTools) Md5Encrypt(msg string) (string, error) {
	tools.md5Tools = md5.New()
	/*h.Write([]byte(msg)) // 需要加密的字符串为 123456
	cipherStr := h.Sum(nil)*/
	cipherStr := tools.md5Tools.Sum([]byte(msg))
	// 输出加密结果 grammar : []byte 使用 %b 的输出
	//fmt.Printf("加密前：%b -----, 加密后：%s\n", cipherStr, hex.EncodeToString(cipherStr))
	return hex.EncodeToString(cipherStr), nil
}

// https://blog.csdn.net/qq_28058509/article/details/120997693
func (tools *EncryptTools) RsaDecrypt(msg string) ([]byte, error) {
	if tools.privateKey == nil {
		return nil, errors.New("privateKey == nil")
	}
	decryptedBytes, err := tools.privateKey.Decrypt(nil, []byte(msg), &rsa.OAEPOptions{Hash: crypto.SHA256})
	if err != nil {
		panic(err)
	}
	//fmt.Printf("rsa 解密:%s\n", decryptedBytes)
	return decryptedBytes, nil
}

func (tools *EncryptTools) RsaEncrypt(msg string) ([]byte, error) {
	//生成私钥
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(err)
	}
	tools.privateKey = key
	//生成公钥
	publicKey := tools.privateKey.PublicKey
	encryptedBytes, err := rsa.EncryptOAEP(
		sha256.New(),
		rand.Reader,
		&publicKey,
		[]byte(msg), //需要加密的字符串
		nil)
	//decryptedBytes, err := privateKey.Decrypt(nil, encryptedBytes, &rsa.OAEPOptions{Hash: crypto.SHA256})
	//fmt.Printf("rsa 加密:%b,------,\nrsa 解密:%s\n", encryptedBytes, decryptedBytes)
	return encryptedBytes, nil
}

// Encrypt ase256 gcm Encrypt.
func (tools *EncryptTools) Ase256Encrypt(plaintext, key, nonce []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonceNew := make([]byte, 12)
	if _, err = rand.Read(nonceNew); err != nil {
		return nil, err
	}
	ciphertext := aesgcm.Seal(nonceNew, nonceNew, plaintext, nil)
	return ciphertext, nil
}

// Decrypt ase256 gcm Decrypt.
func (tools *EncryptTools) Ase256Decrypt(chipertext, key, nonce []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if len(chipertext) > 12 {
		nonceNew, chipertextNew := chipertext[:12], chipertext[12:]
		if plaintext, err1 := aesgcm.Open(nil, nonceNew, chipertextNew, nil); err1 == nil {
			return plaintext, nil
		}
	}

	plaintext, err := aesgcm.Open(nil, nonce, chipertext, nil)
	if err != nil {
		return nil, err
	}
	return plaintext, nil
}

func EEE(msg string) {
	//x509解码
	publicKeyInterface, err := x509.ParsePKIXPublicKey(nil)
	if err != nil {
		panic(err)
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(msg))
	if err != nil {
		panic(err)
	}
	fmt.Println(cipherText)
}

// RSA加密https://www.cnblogs.com/xuweiqiang/p/16336170.html
func RSA_Encrypt(plainText []byte, path string) []byte {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	//读取文件的内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码
	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
	if err != nil {
		panic(err)
	}
	//返回密文
	return cipherText
}

// RSA解密
func RSA_Decrypt(cipherText []byte, path string) []byte {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	//获取文件内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	//对密文进行解密
	plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), cipherText)
	//返回明文
	return plainText
}